/**
 * Copyright (c) 2008 Luciano Bustos - riaevolution.com, All Rights Reserved.
 *
 * Contact luchyx@riaevolution.com
 * See www.riaevolution.com
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is furnished to do
 * so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 * */
package com.riaevolution.components.iconhelp
{
	import flash.display.DisplayObject;
	import flash.events.Event;
	import flash.events.IEventDispatcher;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.net.URLRequest;
	import flash.net.navigateToURL;
	import flash.utils.clearTimeout;
	import flash.utils.setTimeout;
	
	import mx.containers.Canvas;
	import mx.core.UIComponent;
	import mx.effects.Effect;
	import mx.effects.Fade;
	import mx.events.EffectEvent;
	import mx.events.MoveEvent;
	import mx.events.ResizeEvent;
	import mx.managers.PopUpManager;
	import mx.managers.ToolTipManager;
	import mx.styles.CSSStyleDeclaration;
	import mx.styles.StyleManager;

	[Style(name="icon", type="Class", inherit="no")]
	[Style(name="helpIconWindowStyleName", type="String", inherit="no", default="")]
	/**
	 * HelpIcon es una utilidad similar a tooltip pero con un icono activador.
	 * Permite colocar un icon y al hacer rollover sobre este aparece inmediatamente un panel inline sin afectar el tamaño del componente.
	 * <listing>
	 * &lt;local:HelpIcon icon="{yourIconEmbed}"
	 * 		title="SKU definition"
	 * 		content="{_content}"
	 * 		id="tete"/&gt;
	 * </listing>
	 *
	 * <h2>Using a load strategy to display content</h2>
	 * This sample shows you how to load a content from WIKIPEDIA (definition of Tooltip)<br />
	 *
	 * <listing>
	 * &lt;iconhelp:HelpIcon title="Tooltip"
	 * 	footer="{link}"
	 * 	link="http://es.wikipedia.org/wiki/Tooltip"
	 * 	loadStrategy="{new WikipediLoadStrategy()}"/&gt;
	 * </listing><br />
	 * By extending <b>HelpStrategy</b> you can load content from any place on the web. Just implement you own parsing code.
	 *
	 * @see HelpStrategy
	 * @author Luciano Bustos
	 */
	public class HelpIcon extends Canvas
	{

		/**
		 * The default icon window class
		 */
		public static const iconWindowClass:Class=HelpIconWindow;

		[Embed(source="help_icon_box.gif")]
		private static var defaultIcon:Class;

		public function HelpIcon()
		{
			super();
			doubleClickEnabled=true;
			addEventListener(MouseEvent.ROLL_OVER, handleRollOver);
			addEventListener(MouseEvent.ROLL_OUT, handleSelfOut);
			
			addEventListener(MouseEvent.DOUBLE_CLICK, handleDoubleClick);
			addEventListener(MouseEvent.CLICK, showInline);
		}
		
		/**
		 * Initialize default styles
		 */
		private static var classConstructed:Boolean=classConstruct();
		
		
		/**
		 * Initialize default styles
		 * Styles initialization
		 */
		private static function classConstruct():Boolean
		{
			// Check if a CSSStyleDeclaration exists for the component
			var style:CSSStyleDeclaration=StyleManager.getStyleDeclaration("HelpIcon");
			if (!style)
			{
				// If not, create a new one
				style=new CSSStyleDeclaration();
				// and set style default values using an inline function
				style.defaultFactory=function():void
				{
					// Template:
					// this.<myStyle> = <styleDefaultValue>;
					this.icon=defaultIcon;
					//this.normalAlpha = .5;
				};
				
				// Assign the style declaration
				StyleManager.setStyleDeclaration("HelpIcon", style, true);
			}
			else
			{
				// Ensure that default values exist for all our style properties
				if (style.getStyle("icon") == undefined)
				{
					style.setStyle("icon", defaultIcon);
				}
				/*if (style.getStyle("normalAlpha") == undefined)
				{
					style.setStyle("normalAlpha", .5);
				}*/
			}
			return true;
		}

		private var _rollOverTO:int;
		private var _rollOutTO:int;


		/**
		 * The content HTMl supported to display inline
		 */
		public function get content():String
		{
			return _content;
		}

		/**
		 * @private
		 */
		public function set content(value:String):void
		{
			_content=value;
			_contentChange=true;
			invalidateProperties();
		}

		/**
		 * The main title to display
		 */
		public function get title():String
		{
			return _title;
		}

		/**
		 * @private
		 */
		public function set title(value:String):void
		{
			_title=value;
			_titleChange=true;
			invalidateProperties();
		}

		protected function handleDoubleClick(event:Event):void
		{
			if (this.loadStrategy != null)
			{
				this.loadStrategy.load(this);
			}
			else
			{
				navigateToURL(new URLRequest(this.link), "_blank");
			}
		}

		protected function onMoveMe(event:Event):void
		{
			updatePosition();
		}

		/**
		 * When the user roll out the help icon (maybe the window not exist) 
		 */		
		protected function handleSelfOut(event:MouseEvent):void
		{
			if (_rollOverTO)
			{
				clearTimeout(_rollOverTO);
			}
			//this.alpha = this.getStyle('normalAlpha');
		}
		/**
		 * When the user roll over the icon and activa the inline window display. 
		 */
		protected function handleRollOver(event:MouseEvent):void
		{
			if (_rollOverTO)
			{
				clearTimeout(_rollOverTO);
			}
			if (_rollOutTO)
			{
				clearTimeout(_rollOutTO);
			}
			//tarda igual que el tooltip manager
			_rollOverTO=setTimeout(showInline, ToolTipManager.showDelay);
			//this.alpha = 1;
		}
		/**
		 * When the user roll out the help window (not the icon) 
		 */
		protected function handleRollOut(event:MouseEvent):void
		{
			clearTimeout(_rollOverTO);
			if (_rollOutTO)
			{
				clearTimeout(_rollOutTO);
			}
			//se cierra en 100ms
			_rollOutTO=setTimeout(hideInline, 100);
		}

		/**
		 * Create the advanced modal window
		 * @return
		 */
		protected function crateModalWindow():IHelpIconWindow
		{
			return new iconWindowClass();
		}
		/**
		 * Ventanita de infow window
		 */
		protected var helpIconWindowInst:IHelpIconWindow;

		/**
		 * Hide the info window not the icon
		 */
		public function hide():void
		{
			hideInline();
		}

		private var _title:String;
		private var _titleChange:Boolean=false;

		private var _content:String;
		private var _contentChange:Boolean=false;
		/**
		 * The footer of this help. Ofthen a link to a detailed content
		 */
		public var footer:String;
		/**
		 * Related link when the double click the icon.
		 */
		public var link:String;

		/**
		 * Update the component position
		 */
		protected function updatePosition():void
		{
			if (this.parent && this.helpIconWindowInst)
			{
				var pt:Point=this.localToGlobal(new Point());
				//helpIconWindowInst.x=pt.x;
				//helpIconWindowInst.y=pt.y;
				helpIconWindowInst.move(pt.x, pt.y);
			}
		}

		/**
		 * Show the inline info window
		 *
		 * @param title to be setted
		 * @param content html Content to be displayed
		 * @param footer the footer text.
		 *
		 */
		public function show(title:String=null, content:String=null, footer:String=null):void
		{
			if (title)
			{
				this.title=title;
			}
			if (content)
			{
				this.content=content;
			}
			if (footer)
			{
				this.footer=footer;
			}
			showInline();
		}

		private static var _defaultLoadStrategy:HelpStrategy=null;

		/**
		 * Set this to a default strategy custom for your proyect.
		 * This is helpfull if you need the same load strategy across the project
		 *
		 * <listing>
		 * HelpIcon.defaultLoadStrategy = new ConfluenceWikiLoadStrategy();
		 * </listing>
		 *
		 * Remember to extends  HelpStrategy
		 * @param loadStrategy
		 * @see HelpStrategy
		 */
		public static function set defaultLoadStrategy(loadStrategy:HelpStrategy):void
		{
			_defaultLoadStrategy=loadStrategy;
		}

		private var _loadStrategy:Object;

		[Bindable]
		public function set loadStrategy(strategy:Object):void
		{
			_loadStrategy=strategy;
		}

		/**
		 * getter for the tooltip content load strategy
		 * @return
		 */
		public function get loadStrategy():Object
		{
			if (_loadStrategy != null)
			{
				return _loadStrategy;
			}
			else if (_defaultLoadStrategy != null)
			{
				return _defaultLoadStrategy;
			}
			else
			{
				return null;
			}
		}

		/**
		 * Mostrar en el tooltip window inline.
		 * @param e
		 */
		protected function showInline(e:Event=null):void
		{
			if (_rollOverTO)
			{
				clearTimeout(_rollOverTO);
			}
			if (_rollOutTO)
			{
				clearTimeout(_rollOutTO);
			}
			if (helpIconWindowInst)
			{
				helpIconWindowInst.description=this.content;
				helpIconWindowInst.title=this.title;
				helpIconWindowInst.footer=this.footer;
				helpIconWindowInst.iconHeight=this.height;
				helpIconWindowInst.iconWidth=this.width;
				helpIconWindowInst.icon=this.getIconUI();
				return;
			}

			helpIconWindowInst=crateModalWindow();
			helpIconWindowInst.alpha=0;

			helpIconWindowInst.description=this.content;
			helpIconWindowInst.title=this.title;
			helpIconWindowInst.footer=this.footer;
			helpIconWindowInst.iconHeight=this.height;
			helpIconWindowInst.iconWidth=this.width;
			helpIconWindowInst.icon=this.getIconUI();
			//si tengo styleName
			if(this.getStyle('helpIconWindowStyleName') != undefined) {
				helpIconWindowInst.styleName = this.getStyle('helpIconWindowStyleName');
			}

			helpIconWindowInst.addEventListener(MouseEvent.ROLL_OUT, handleRollOut);

			if (loadStrategy && this.link)
			{
				loadStrategy.load(this);
			}
			updatePosition();

			PopUpManager.addPopUp(helpIconWindowInst, this);


			//addChildAt(helpIconWindowInst as DisplayObject, 0);

			var ef:Fade=new Fade();
			ef.alphaFrom=0;
			ef.alphaTo=1;
			ef.play([helpIconWindowInst]);

		}

		/**
		 * hide the component
		 * this method is automtically called whe user roll out
		 */
		protected function hideInline():void
		{
			if (helpIconWindowInst)
			{
				var ef:Fade=new Fade();
				ef.alphaFrom=1;
				ef.alphaTo=0;
				ef.play([helpIconWindowInst]);
				ef.addEventListener(EffectEvent.EFFECT_END, removeInline);
			}
		}

		/**
		 * @private
		 */
		protected function removeInline(event:EffectEvent):void
		{
			(event.currentTarget as Effect).removeEventListener(EffectEvent.EFFECT_END, removeInline);
			if (helpIconWindowInst)
			{
				helpIconWindowInst.removeEventListener(MouseEvent.ROLL_OUT, handleRollOut);
				PopUpManager.removePopUp(helpIconWindowInst);
				helpIconWindowInst=null;
			}
		}

		/**
		 * Getter for the icon class
		 * @return
		 *
		 */
		override public function get icon():Class
		{
			var cl:Class=super.icon;
			return cl ? cl : defaultIcon;
		}

		override public function set icon(value:Class):void
		{
			super.icon=value;
			_iconChanged=true;
			invalidateProperties();
		}

		private var _iconChanged:Boolean=false;

		/**
		 * @inheritDoc
		 */
		override public function styleChanged(styleProp:String):void
		{
			super.styleChanged(styleProp);
			if (styleProp == 'icon')
			{
				this.icon=getStyle(styleProp);
			}
		}

		/**
		 * get an icon instance specified by CSS or Embed
		 */
		protected function getIconUI():UIComponent
		{
			var cl:Object=new icon();

			var helpIconWindowInst:UIComponent=new UIComponent();
			helpIconWindowInst.width=cl.width;
			helpIconWindowInst.height=cl.height;
			helpIconWindowInst.addChild(cl as DisplayObject);

			return helpIconWindowInst;
		}

		/**
		 * @inheritDoc
		 */
		override protected function commitProperties():void
		{
			super.commitProperties();
			if (_titleChange && helpIconWindowInst)
			{
				helpIconWindowInst.title=this.title;
				_titleChange=false;
			}
			if (_contentChange && helpIconWindowInst)
			{
				helpIconWindowInst.description=this.content;
				_contentChange=false;
			}
			if (_iconChanged)
			{
				_iconChanged=false;
				var iconUI:DisplayObject=this.getChildByName('iconUI');
				if (iconUI)
				{
					removeChild(iconUI);
				}
				addIconComponent();
			}
		}
		/**
		 * @inheritDoc
		 */
		override protected function createChildren():void
		{
			super.createChildren();
			this.icon=getStyle('icon');
			addIconComponent();
		}
		/**
		 * Add the small icon to the display list 
		 */
		protected function addIconComponent():void
		{
			var ui:UIComponent=getIconUI();
			ui.name="iconUI";
			addChild(ui);
		}
	}
}